/**
 * \file Acpi.cc
 * \brief Kernel ACPI interface and Intel ACPI CA OS Services Layer (OSL)
 * \author Corey Tabaka
 */

/*
   Copyright 2005 Corey Tabaka

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include <ktypes.h>
#include <platform/Acpi.h>
#include <platform/Interrupt.h>
#include <platform/Memory.h>
#include <platform/Pic.h>
#include <platform/Pci.h>
#include <platform/Timer.h>
#include <Thread.h>
#include <Process.h>
#include <Sync.h>
#include <Log.h>
#include <syscall.h>

#include <i386/io.h>
#include <i386/console.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include <malloc.h>

extern "C" {

#include <acpica/include/acpi.h>
#include <acpica/include/amlcode.h>
#include <acpica/include/acparser.h>
#include <acpica/include/acdebug.h>
#include <acpica/include/acglobal.h>

}

static RSDP_DESCRIPTOR				*LocalRSDP;

static struct {
	ACPI_OSD_HANDLER handler;
	void *context;
} OSLInterruptHandlers[16];
	
static bool interruptHandler(regs_t *regs);
static ACPI_STATUS walkCallback(ACPI_HANDLE handle, UINT32 depth, void *ctx,
	void **ret);

/*
 * ACPI intitialization
 */
void Acpi::initialize(void) {
	//Log::printf(LOG_MEDIUM, "    Initializing ACPI manager\n");
	
	ACPI_STATUS status;
	
	status = AcpiInitializeSubsystem();
	if (ACPI_FAILURE(status)) {
		Log::printf(LOG_MEDIUM, "Failed to initialize ACPI CA: %s\n",
			AcpiFormatException(status));
		return;
	}
	
	ACPI_POINTER rsdp;
	status = AcpiFindRootPointer(0, &rsdp);
	if (ACPI_FAILURE(status)) {
		Log::printf(LOG_MEDIUM, "RSDP structure not found, %s\n",
			AcpiFormatException(status));
		return;
	}
	
	if (rsdp.Pointer.Physical) {
		LocalRSDP = (RSDP_DESCRIPTOR *) (uint32) rsdp.Pointer.Physical;
		Log::printf(LOG_MEDIUM, "RSDP Revision %u (%08x)\n",
			LocalRSDP->Revision, LocalRSDP);
	}
	
	status = AcpiLoadTables();
	if (ACPI_FAILURE(status)) {
		Log::printf(LOG_MEDIUM, "Failed to load tables: %s\n",
			AcpiFormatException(status));
		return;
	}
	
	status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
	if (ACPI_FAILURE(status)) {
		Log::printf(LOG_MEDIUM, "Failed to enable subsystem: %s\n",
			AcpiFormatException(status));
		return;
	}
	
	status = AcpiInitializeObjects(0);
	if (ACPI_FAILURE(status)) {
		Log::printf(LOG_MEDIUM, "Failed to initialize objects: %s\n",
			AcpiFormatException(status));
		return;
	}
	
	status = AcpiEnable();
	if (ACPI_FAILURE(status)) {
		Log::printf(LOG_MEDIUM, "Failed to enable ACPI: %s\n",
			AcpiFormatException(status));
		return;
	}
	
	status = AcpiGetDevices(0, walkCallback, 0, 0);
	if (ACPI_FAILURE(status)) {
		Log::printf(LOG_MEDIUM, "Failed to get devices: %s\n",
			AcpiFormatException(status));
		return;
	}
	
	UINT32 state = 0;
	status = AcpiGetRegister(ACPI_BITREG_SCI_ENABLE, &state, ACPI_MTX_LOCK);
	if (ACPI_FAILURE(status)) {
		Log::printf(LOG_MEDIUM, "Failed to get register: %s\n",
			AcpiFormatException(status));
		return;
	}
	
	Log::printf(LOG_MEDIUM, "ACPI_BITREG_SCI_ENABLE = %d\n", state);
}

static bool interruptHandler(regs_t *regs) {
	if (regs->which_int >= INT_BASE && regs->which_int < INT_BASE + 16) {
		printf_xy(regs->which_int*3, 23, WHITE, "%02x ", regs->which_int);
		
		uint32 interrupt = regs->which_int - INT_BASE;
		
		if (OSLInterruptHandlers[interrupt].handler) {
			Log::printf(LOG_MEDIUM, "SCI interrupt %u\n", interrupt);
			
			OSLInterruptHandlers[interrupt].handler(
				OSLInterruptHandlers[interrupt].context);
			
			return true;
		}
	}
	
	return false;
}

static ACPI_STATUS walkCallback(ACPI_HANDLE handle, UINT32 depth, void *ctx,
	void **ret) {
	static char path[64];
	static char name[64];
	
	ACPI_BUFFER buffer;
	ACPI_STATUS status;
	
	buffer.Length = sizeof(path);
	buffer.Pointer = path;
	
	status = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buffer);
	if (ACPI_FAILURE(status)) {
		Log::printf(LOG_MEDIUM, "Failed to get path: %s\n",
			AcpiFormatException(status));
		return AE_OK;
	}
	
	buffer.Length = sizeof(name);
	buffer.Pointer = name;
	
	status = AcpiGetName(handle, ACPI_SINGLE_NAME, &buffer);
	if (ACPI_FAILURE(status)) {
		Log::printf(LOG_MEDIUM, "Failed to get name: %s\n",
			AcpiFormatException(status));
		return AE_OK;
	}
	
	Log::printf(LOG_MEDIUM, "%s\n", path);
	
	//task_sleep(200);
	
	if (!strcmp("PCI0", name)) {
		buffer.Length = ACPI_ALLOCATE_BUFFER;
		buffer.Pointer = 0;
		
		status = AcpiGetIrqRoutingTable(handle, &buffer);
		if (ACPI_FAILURE(status)) {
			Log::printf(LOG_MEDIUM, "Failed to get IRQ routing table: %s\n",
				AcpiFormatException(status));
			return AE_OK;
		}
		
		uint8 *table = (uint8 *) buffer.Pointer;
		ACPI_PCI_ROUTING_TABLE *pci = (ACPI_PCI_ROUTING_TABLE *) table;
		while (pci->Length) {
			Log::printf(LOG_MEDIUM, "IRQ: %08x %d %d %s\n",
				(uint32) pci->Address, pci->Pin, pci->SourceIndex, pci->Source);
			table = table + pci->Length;
			pci = (ACPI_PCI_ROUTING_TABLE *) table;
		}
		
		//task_wait();
		
		free(buffer.Pointer);
	}
	
	return AE_OK;
}


extern "C" {

/*
 * These interfaces are required in order to compile the ASL compiler under
 * Monarc Core.
 */

#define _COMPONENT          ACPI_OS_SERVICES
        ACPI_MODULE_NAME    ("osunixxf")

/******************************************************************************
 *
 * FUNCTION:    AcpiOsInitialize, AcpiOsTerminate
 *
 * PARAMETERS:  None
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Init and terminate.  Nothing to do.
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsInitialize (void)
{
    return AE_OK;
}


ACPI_STATUS
AcpiOsTerminate (void)
{
    return AE_OK;
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsGetRootPointer
 *
 * PARAMETERS:  Flags   - Logical or physical addressing mode
 *              Address - Where the address is returned
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Gets the root pointer (RSDP)
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsGetRootPointer (
    UINT32                  Flags,
    ACPI_POINTER           *Address)
{

    Address->PointerType     = ACPI_LOGICAL_POINTER;
    Address->Pointer.Logical = LocalRSDP;
    return (AE_OK);
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsPredefinedOverride
 *
 * PARAMETERS:  InitVal     - Initial value of the predefined object
 *              NewVal      - The new value for the object
 *
 * RETURN:      Status, pointer to value.  Null pointer returned if not
 *              overriding.
 *
 * DESCRIPTION: Allow the OS to override predefined names
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsPredefinedOverride (
    const ACPI_PREDEFINED_NAMES *InitVal,
    ACPI_STRING                 *NewVal)
{

    if (!InitVal || !NewVal)
    {
        return (AE_BAD_PARAMETER);
    }

    *NewVal = NULL;
    return (AE_OK);
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsTableOverride
 *
 * PARAMETERS:  ExistingTable   - Header of current table (probably firmware)
 *              NewTable        - Where an entire new table is returned.
 *
 * RETURN:      Status, pointer to new table.  Null pointer returned if no
 *              table is available to override
 *
 * DESCRIPTION: Return a different version of a table if one is available
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsTableOverride (
    ACPI_TABLE_HEADER       *ExistingTable,
    ACPI_TABLE_HEADER       **NewTable)
{

    if (!ExistingTable || !NewTable)
    {
        return (AE_BAD_PARAMETER);
    }
    
    const char *sig = ExistingTable->Signature;
    Log::printf(LOG_MEDIUM, "Table %c%c%c%c\n", sig[0], sig[1], sig[2], sig[3]);

    *NewTable = NULL;
    
    return (AE_OK);

#ifdef ACPI_EXEC_APP

    /* This code exercises the table override mechanism in the core */

    if (!ACPI_STRNCMP (ExistingTable->Signature, DSDT_SIG, ACPI_NAME_SIZE))
    {
        /* override DSDT with itself */

        *NewTable = AcpiGbl_DbTablePtr;
    }
    return (AE_OK);
//#else
//    return AE_NO_ACPI_TABLES;
#endif
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsReadable
 *
 * PARAMETERS:  Pointer             - Area to be verified
 *              Length              - Size of area
 *
 * RETURN:      TRUE if readable for entire length
 *
 * DESCRIPTION: Verify that a pointer is valid for reading
 *
 *****************************************************************************/

BOOLEAN
AcpiOsReadable (
    void                    *Pointer,
    ACPI_SIZE               Length)
{

    return (TRUE);
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsWritable
 *
 * PARAMETERS:  Pointer             - Area to be verified
 *              Length              - Size of area
 *
 * RETURN:      TRUE if writable for entire length
 *
 * DESCRIPTION: Verify that a pointer is valid for writing
 *
 *****************************************************************************/

BOOLEAN
AcpiOsWritable (
    void                    *Pointer,
    ACPI_SIZE               Length)
{

    return (TRUE);
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsRedirectOutput
 *
 * PARAMETERS:  Destination         - An open file handle/pointer
 *
 * RETURN:      None
 *
 * DESCRIPTION: Causes redirect of AcpiOsPrintf and AcpiOsVprintf
 *
 *****************************************************************************/

void
AcpiOsRedirectOutput (
    void                    *Destination)
{

}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsPrintf
 *
 * PARAMETERS:  fmt, ...            Standard printf format
 *
 * RETURN:      None
 *
 * DESCRIPTION: Formatted output
 *
 *****************************************************************************/

void ACPI_INTERNAL_VAR_XFACE
AcpiOsPrintf (
    const char              *Fmt,
    ...)
{
    va_list                 Args;


    va_start (Args, Fmt);

    AcpiOsVprintf (Fmt, Args);

    va_end (Args);
    return;
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsVprintf
 *
 * PARAMETERS:  fmt                 Standard printf format
 *              args                Argument list
 *
 * RETURN:      None
 *
 * DESCRIPTION: Formatted output with argument list pointer
 *
 *****************************************************************************/

void
AcpiOsVprintf (
    const char              *Fmt,
    va_list                 Args)
{
    INT32                   Count = 0;
    UINT8                   Flags;


    Flags = AcpiGbl_DbOutputFlags;
    if (Flags & ACPI_DB_REDIRECTABLE_OUTPUT)
    {
        /* Output is directable to either a file (if open) or the console */

        /* No redirection, send output to console (once only!) */

        Flags |= ACPI_DB_CONSOLE_OUTPUT;
    }

    if (Flags & ACPI_DB_CONSOLE_OUTPUT)
    {
    	char buffer[1024];
        Count = vsprintf (buffer, (char *) Fmt, Args);
        
        buffer[1023] = '\0';
        Log::printf(LOG_MEDIUM, "%s", buffer);
    }

    return;
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsGetLine
 *
 * PARAMETERS:  fmt                 Standard printf format
 *              args                Argument list
 *
 * RETURN:      Actual bytes read
 *
 * DESCRIPTION: Formatted input with argument list pointer
 *
 *****************************************************************************/

UINT32
AcpiOsGetLine (
    char                    *Buffer)
{
#if 0
    UINT8                   Temp;
    UINT32                  i;

    for (i = 0; ; i++)
    {
        scanf ("%1c", &Temp);
        if (!Temp || Temp == '\n')
        {
            break;
        }

        Buffer [i] = Temp;
    }

    /* Null terminate the buffer */

    Buffer [i] = 0;

    /* Return the number of bytes in the string */

    return (i);
#endif
	
	return 0;
}

/******************************************************************************
 *
 * FUNCTION:    AcpiOsMapMemory
 *
 * PARAMETERS:  where               Physical address of memory to be mapped
 *              length              How much memory to map
 *              there               Logical address of mapped memory
 *
 * RETURN:      Pointer to mapped memory.  Null on error.
 *
 * DESCRIPTION: Map physical memory into caller's address space
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsMapMemory (
    ACPI_PHYSICAL_ADDRESS   where,
    ACPI_SIZE               length,
    void                    **there)
{
	if (ACPI_TO_POINTER(where) < (void *) MEM_IDENTITY_MAP_SIZE) {
    	*there = ACPI_TO_POINTER (where);
    } else {
    	RefProcess proc = Process::getSystemProcess();
    	//*there = proc->getPageTable().acquire(ACPI_TO_POINTER(where),
    	//	ACPI_TO_POINTER(where), length, false);
    	
    	Region *region = proc->getAddressSpace().create(
    		(uint32) ACPI_TO_POINTER(where), (uint32) ACPI_TO_POINTER(where),
    		length, REGION_FLAGS_CONTIG, REGION_TYPE_MAPPING);
    	
    	*there = (void *) region->getVirtualBase();
    }

    return AE_OK;
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsUnmapMemory
 *
 * PARAMETERS:  where               Logical address of memory to be unmapped
 *              length              How much memory to unmap
 *
 * RETURN:      None.
 *
 * DESCRIPTION: Delete a previously created mapping.  Where and Length must
 *              correspond to a previous mapping exactly.
 *
 *****************************************************************************/

void
AcpiOsUnmapMemory (
    void                    *where,
    ACPI_SIZE               length)
{

    if (ACPI_TO_POINTER(where) >= (void *) MEM_IDENTITY_MAP_SIZE) {
    	RefProcess proc = Process::getSystemProcess();
    	Region *region = proc->getAddressSpace().findVirtual((uint32) where);
    	
    	if (region && (void *) region->getVirtualBase() == where
    		&& region->getSize() == length) {
    		proc->getAddressSpace().destroy(region);
    		region = 0;
    	}
    }
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsAllocate
 *
 * PARAMETERS:  Size                Amount to allocate, in bytes
 *
 * RETURN:      Pointer to the new allocation.  Null on error.
 *
 * DESCRIPTION: Allocate memory.  Algorithm is dependent on the OS.
 *
 *****************************************************************************/

void *
AcpiOsAllocate (
    ACPI_SIZE               size)
{
    void                    *Mem;


    Mem = (void *) malloc ((size_t) size);

    return Mem;
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsFree
 *
 * PARAMETERS:  mem                 Pointer to previously allocated memory
 *
 * RETURN:      None.
 *
 * DESCRIPTION: Free memory allocated via AcpiOsAllocate
 *
 *****************************************************************************/

void
AcpiOsFree (
    void                    *mem)
{


    free (mem);
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsCreateSemaphore
 *
 * PARAMETERS:  InitialUnits        - Units to be assigned to the new semaphore
 *              OutHandle           - Where a handle will be returned
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Create an OS semaphore
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsCreateSemaphore (
    UINT32              MaxUnits,
    UINT32              InitialUnits,
    ACPI_HANDLE         *OutHandle)
{


    *OutHandle = (ACPI_HANDLE) 1;
    return AE_OK;
}

/******************************************************************************
 *
 * FUNCTION:    AcpiOsDeleteSemaphore
 *
 * PARAMETERS:  Handle              - Handle returned by AcpiOsCreateSemaphore
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Delete an OS semaphore
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsDeleteSemaphore (
    ACPI_HANDLE         Handle)
{

    if (!Handle)
    {
        return AE_BAD_PARAMETER;
    }

    return AE_OK;
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsWaitSemaphore
 *
 * PARAMETERS:  Handle              - Handle returned by AcpiOsCreateSemaphore
 *              Units               - How many units to wait for
 *              Timeout             - How long to wait
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Wait for units
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsWaitSemaphore (
    ACPI_HANDLE         Handle,
    UINT32              Units,
    UINT16              Timeout)
{


    return AE_OK;
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsSignalSemaphore
 *
 * PARAMETERS:  Handle              - Handle returned by AcpiOsCreateSemaphore
 *              Units               - Number of units to send
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Send units
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsSignalSemaphore (
    ACPI_HANDLE         Handle,
    UINT32              Units)
{


    return AE_OK;
}


ACPI_STATUS
AcpiOsCreateLock (
    ACPI_HANDLE             *OutHandle)
{

    return (AcpiOsCreateSemaphore (1, 1, OutHandle));
}

void
AcpiOsDeleteLock (
    ACPI_HANDLE             Handle)
{
    AcpiOsDeleteSemaphore (Handle);
}


ACPI_NATIVE_UINT
AcpiOsAcquireLock (
    ACPI_HANDLE             Handle)
{
    AcpiOsWaitSemaphore (Handle, 1, 0xFFFF);
    return (0);
}


void
AcpiOsReleaseLock (
    ACPI_HANDLE             Handle,
    ACPI_NATIVE_UINT        Flags)
{
    AcpiOsSignalSemaphore (Handle, 1);
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsInstallInterruptHandler
 *
 * PARAMETERS:  InterruptNumber     Level handler should respond to.
 *              Isr                 Address of the ACPI interrupt handler
 *              ExceptPtr           Where status is returned
 *
 * RETURN:      Handle to the newly installed handler.
 *
 * DESCRIPTION: Install an interrupt handler.  Used to install the ACPI
 *              OS-independent handler.
 *
 *****************************************************************************/

UINT32
AcpiOsInstallInterruptHandler (
    UINT32                  InterruptNumber,
    ACPI_OSD_HANDLER        ServiceRoutine,
    void                    *Context)
{
	Log::printf(LOG_MEDIUM, "Install interrupt handler: int=%u, handler=%08x\n",
		InterruptNumber, (UINT32) ServiceRoutine);
	
	if (InterruptNumber < 16) {
		OSLInterruptHandlers[InterruptNumber].handler = ServiceRoutine;
		OSLInterruptHandlers[InterruptNumber].context = Context;
		
		Interrupt::registerHandler(InterruptNumber + INT_BASE,
			interruptHandler);
		
		return AE_OK;
	}
	
	return AE_ERROR;
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsRemoveInterruptHandler
 *
 * PARAMETERS:  Handle              Returned when handler was installed
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Uninstalls an interrupt handler.
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsRemoveInterruptHandler (
    UINT32                  InterruptNumber,
    ACPI_OSD_HANDLER        ServiceRoutine)
{

    return AE_OK;
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsQueueForExecution
 *
 * PARAMETERS:  Priority        - Requested execution priority
 *              Function        - Address of the function to execute
 *              Context         - Passed as a parameter to the function
 *
 * RETURN:      Status.
 *
 * DESCRIPTION: Sleep at microsecond granularity
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsQueueForExecution (
    UINT32                  Priority,
    ACPI_OSD_EXEC_CALLBACK  Function,
    void                    *Context)
{
	Log::printf(LOG_MEDIUM, "new task: pri=%u, function=%08x\n", Priority,
		(uint32) Function);
//    _beginthread (Function, (unsigned) 0, Context);
    return 0;
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsBreakpoint
 *
 * PARAMETERS:  Msg                 Message to print
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Print a message and break to the debugger.
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsBreakpoint (
    char                    *Msg)
{

    /* Print the message and do an INT 3 */

    if (Msg)
    {
        AcpiOsPrintf ("AcpiOsBreakpoint: %s ****\n", Msg);
    }
    else
    {
        AcpiOsPrintf ("At AcpiOsBreakpoint ****\n");
    }


    return AE_OK;
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsStall
 *
 * PARAMETERS:  microseconds        To sleep
 *
 * RETURN:      Blocks until sleep is completed.
 *
 * DESCRIPTION: Sleep at microsecond granularity
 *
 *****************************************************************************/

void
AcpiOsStall (
    UINT32                  microseconds)
{

    if (microseconds)
    {
        USLEEP (microseconds);
    }
    return;
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsSleep
 *
 * PARAMETERS:  milliseconds        To sleep
 *
 * RETURN:      Blocks until sleep is completed.
 *
 * DESCRIPTION: Sleep at millisecond granularity
 *
 *****************************************************************************/

void
AcpiOsSleep (
    ACPI_INTEGER            milliseconds)
{

    SLEEP (milliseconds);

    /*
     * Arg to usleep() must be less than 1,000,000 (1 second)
     */
    USLEEP ((milliseconds % 1000) * 1000);      /* Sleep for remaining usecs */

    return;
}

/******************************************************************************
 *
 * FUNCTION:    AcpiOsGetTimer
 *
 * PARAMETERS:  None
 *
 * RETURN:      Current time in 100 nanosecond units
 *
 * DESCRIPTION: Get the current system time
 *
 *****************************************************************************/

UINT64
AcpiOsGetTimer (void)
{
    
    return Timer::getMicroTime() * 10;
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsReadPciConfiguration
 *
 * PARAMETERS:  PciId               Seg/Bus/Dev
 *              Register            Device Register
 *              Value               Buffer where value is placed
 *              Width               Number of bits
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Read data from PCI configuration space
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsReadPciConfiguration (
    ACPI_PCI_ID             *PciId,
    UINT32                  Register,
    void                    *Value,
    UINT32                  Width)
{
	pci_location_t loc;
	loc.bus = PciId->Bus;
	loc.device = PciId->Device;
	loc.function = PciId->Function;
	
	switch (Width) {
		case 8:
			Pci::readConfig(loc, Register, (uint8 *) Value);
			break;
		
		case 16:
			Pci::readConfig16(loc, Register, (uint16 *) Value);
			break;
		
		case 32:
			Pci::readConfig32(loc, Register, (uint32 *) Value);
			break;
	}
	
    return (AE_OK);
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsWritePciConfiguration
 *
 * PARAMETERS:  PciId               Seg/Bus/Dev
 *              Register            Device Register
 *              Value               Value to be written
 *              Width               Number of bits
 *
 * RETURN:      Status.
 *
 * DESCRIPTION: Write data to PCI configuration space
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsWritePciConfiguration (
    ACPI_PCI_ID             *PciId,
    UINT32                  Register,
    ACPI_INTEGER            Value,
    UINT32                  Width)
{
	pci_location_t loc;
	loc.bus = PciId->Bus;
	loc.device = PciId->Device;
	loc.function = PciId->Function;
	
	switch (Width) {
		case 8:
			Pci::writeConfig(loc, Register, Value);
			break;
		
		case 16:
			Pci::writeConfig16(loc, Register, Value);
			break;
		
		case 32:
			Pci::writeConfig32(loc, Register, Value);
			break;
	}
	
    return (AE_OK);
}

/* TEMPORARY STUB FUNCTION */
void
AcpiOsDerivePciId(
    ACPI_HANDLE             rhandle,
    ACPI_HANDLE             chandle,
    ACPI_PCI_ID             **PciId)
{

}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsReadPort
 *
 * PARAMETERS:  Address             Address of I/O port/register to read
 *              Value               Where value is placed
 *              Width               Number of bits
 *
 * RETURN:      Value read from port
 *
 * DESCRIPTION: Read data from an I/O port or register
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsReadPort (
    ACPI_IO_ADDRESS         Address,
    UINT32                  *Value,
    UINT32                  Width)
{

    switch (Width)
    {
    case 8:
        *Value = inp(Address);
        break;

    case 16:
        *Value = inpw(Address);
        break;

    case 32:
        *Value = inpd(Address);;
        break;
        
    default:
		return (AE_BAD_PARAMETER);
    }

    return (AE_OK);
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsWritePort
 *
 * PARAMETERS:  Address             Address of I/O port/register to write
 *              Value               Value to write
 *              Width               Number of bits
 *
 * RETURN:      None
 *
 * DESCRIPTION: Write data to an I/O port or register
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsWritePort (
    ACPI_IO_ADDRESS         Address,
    UINT32                  Value,
    UINT32                  Width)
{
	switch (Width)
	{
	case 8:
		outp(Address, Value);
		break;
	
	case 16:
		outpw(Address, Value);
		break;
	
	case 32:
		outpd(Address, Value);
		break;
	
	default:
		return (AE_BAD_PARAMETER);
	}
	
    return (AE_OK);
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsReadMemory
 *
 * PARAMETERS:  Address             Physical Memory Address to read
 *              Value               Where value is placed
 *              Width               Number of bits
 *
 * RETURN:      Value read from physical memory address
 *
 * DESCRIPTION: Read data from a physical memory address
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsReadMemory (
    ACPI_PHYSICAL_ADDRESS   Address,
    UINT32                  *Value,
    UINT32                  Width)
{

    switch (Width)
    {
    case 8:
    	*Value = *(uint8 *) (uint32) Address;
    	break;
    	
    case 16:
    	*Value = *(uint16 *) (uint32) Address;
    	break;
    	
    case 32:
        *Value = *(uint32 *) (uint32) Address;
    	break;

    default:
        return (AE_BAD_PARAMETER);
        break;
    }
    return (AE_OK);
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsWriteMemory
 *
 * PARAMETERS:  Address             Physical Memory Address to write
 *              Value               Value to write
 *              Width               Number of bits
 *
 * RETURN:      None
 *
 * DESCRIPTION: Write data to a physical memory address
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsWriteMemory (
    ACPI_PHYSICAL_ADDRESS   Address,
    UINT32                  Value,
    UINT32                  Width)
{
	switch (Width)
    {
    case 8:
    	*((uint8 *) (uint32) Address) = Value;
    	break;
    	
    case 16:
    	*((uint16 *) (uint32) Address) = Value;
    	break;
    	
    case 32:
        *((uint32 *) (uint32) Address) = Value;
    	break;

    default:
        return (AE_BAD_PARAMETER);
        break;
    }
    
    return (AE_OK);
}


UINT32
AcpiOsGetThreadId(void)
{
    return Thread::getCurrentThread()->getTid();
}


/******************************************************************************
 *
 * FUNCTION:    AcpiOsSignal
 *
 * PARAMETERS:  Function            ACPI CA signal function code
 *              Info                Pointer to function-dependent structure
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Miscellaneous functions
 *
 *****************************************************************************/

ACPI_STATUS
AcpiOsSignal (
    UINT32                  Function,
    void                    *Info)
{

    switch (Function)
    {
    case ACPI_SIGNAL_FATAL:
        break;

    case ACPI_SIGNAL_BREAKPOINT:

        if (Info)
        {
            AcpiOsPrintf ("AcpiOsBreakpoint: %s ****\n", Info);
        }
        else
        {
            AcpiOsPrintf ("At AcpiOsBreakpoint ****\n");
        }

        break;
    }


    return (AE_OK);
}


} // extern "C"
